//
// Created by user on 20-5-5.
//

#include "Semaphore.h"

void waitQueueInit(WaitQueue_T *waitQueue, Task *tsk) {
    listInit(&waitQueue->waitList);
    waitQueue->tsk = tsk;
}

void semaphoreInit(Semaphore_T *semaphore, unsigned long count) {
    atomicSet(&semaphore->counter, count);
    waitQueueInit(&semaphore->wait, NULL);
}

void __up(Semaphore_T *semaphore) {
    WaitQueue_T *wait = containerOf(listNext(&semaphore->wait.waitList), WaitQueue_T, waitList);

    listDel(&wait->waitList);
    wait->tsk->state = TASK_RUNNING;
    insertTaskQueue(wait->tsk);
}

void semaphoreUp(Semaphore_T *semaphore) {
    if (listIsEmpty(&semaphore->wait.waitList))
        atomicInc(&semaphore->counter);
    else
        __up(semaphore);
}

void __down(Semaphore_T *semaphore) {
    WaitQueue_T wait;
    waitQueueInit(&wait, current);
    current->state = TASK_UNINTERRUPTIBLE;
    listAddToBefore(&semaphore->wait.waitList, &wait.waitList);

    schedule();
}

void semaphoreDown(Semaphore_T *semaphore) {
    if (atomicRead(&semaphore->counter) > 0)
        atomicDec(&semaphore->counter);
    else
        __down(semaphore);
}